package com.scaffold.myproject.utils;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.*;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 阿里云 OSS 工具类
 */
@Slf4j
@Component
public class AliOSSUtils {

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.access-key-id}")
    private String accessKeyId;

    @Value("${aliyun.oss.access-key-secret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.bucket-name}")
    private String publicBucket;

    @Value("${aliyun.oss.privateBucket}")
    private String privateBucket;

    private OSS ossClient;


    /**
     * 初始化 OSS 客户端
     */
    @PostConstruct
    public void init() {
        this.ossClient = new OSSClientBuilder()
                .build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 上传字节流到 OSS
     *
     * @param folder      上传目录
     * @param fileName    原始文件名（包括后缀）
     * @param inputStream 文件流
     * @param isPrivate   是否上传到私有桶
     * @return 存储在 OSS 上的相对路径
     */
    public String upload(String folder, String fileName, InputStream inputStream, boolean isPrivate) {
        String target = folder + "/" + rename(fileName);
        ossClient.putObject(new PutObjectRequest(
                isPrivate ? privateBucket : publicBucket,
                target,
                inputStream));
        return target;
    }

    /**
     * 上传 MultipartFile 到 OSS（公有桶）
     *
     * @param file   Spring MultipartFile
     * @param folder 上传目录
     * @return OSS 相对路径
     * @throws IOException IO 异常
     */
    public String upload(MultipartFile file, String folder) throws IOException {
        try (InputStream in = file.getInputStream()) {
            String original = file.getOriginalFilename();
            if (original == null) throw new IllegalArgumentException("文件名为空");
            return upload(folder, original, in, false);
        }
    }

    /**
     * 删除 OSS 上的文件
     *
     * @param path      相对路径
     * @param isPrivate 是否私有桶
     */
    public void delete(String path, boolean isPrivate) {
        ossClient.deleteObject(
                isPrivate ? privateBucket : publicBucket,
                path);
    }

    /**
     * 下载 OSS 文件到本地
     *
     * @param path      相对路径
     * @param destFile  目标本地文件
     * @param isPrivate 是否私有桶
     * @return 下载是否成功
     */
    public boolean downloadToFile(String path, File destFile, boolean isPrivate) {
        try {
            ossClient.getObject(
                    new GetObjectRequest(isPrivate ? privateBucket : publicBucket, path),
                    destFile);
            return true;
        } catch (Exception e) {
            log.error("下载失败: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 下载 OSS 文件为字节数组
     *
     * @param path      相对路径
     * @param isPrivate 是否私有桶
     * @return 文件内容字节数组
     */
    public byte[] downloadToBytes(String path, boolean isPrivate) {
        try (OSSObject obj = ossClient.getObject(
                new GetObjectRequest(isPrivate ? privateBucket : publicBucket, path))) {
            return IOUtils.toByteArray(obj.getObjectContent());
        } catch (Exception e) {
            log.error("下载字节失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 下载 OSS 文件部分内容
     *
     * @param path      相对路径
     * @param isPrivate 是否私有桶
     * @param start     起始字节
     * @param end       结束字节
     * @return 指定范围的字节数组
     * @throws IOException IO 异常
     */
    public byte[] downloadRange(String path, boolean isPrivate, long start, long end) throws IOException {
        GetObjectRequest req = new GetObjectRequest(
                isPrivate ? privateBucket : publicBucket, path);
        req.setRange(start, end);
        try (OSSObject obj = ossClient.getObject(req)) {
            return IOUtils.toByteArray(obj.getObjectContent());
        }
    }

    /**
     * 根据相对路径构造完整访问 URL
     *
     * @param path      相对路径
     * @param isPrivate 是否私有桶
     * @return 完整 URL
     */
    public String getFullUrl(String path, boolean isPrivate) {
        if (path.startsWith("http")) return path;
        String bucket = isPrivate ? privateBucket : publicBucket;
        return "https://" + bucket + "." + endpoint.replace("https://", "") + "/" + path;
    }


    /**
     * 重命名文件（UUID + 后缀）
     *
     * @param fileName 原文件名
     * @return 重命名后的文件名
     */
    public String rename(String fileName) {
        String suffix = fileName.contains(".")
                ? fileName.substring(fileName.lastIndexOf("."))
                : "";
        return UUID.randomUUID().toString().replace("-", "") + suffix;
    }

    /**
     * 关闭 OSS 客户端
     */
    @PreDestroy
    public void destroy() {
        log.info("Shutting down OSS clients...");
        if (ossClient != null) ossClient.shutdown();
    }
}
